﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace System
{
    public static partial class Utility
    {
        private const string NewLineHtml = "<br/>";

        /// <summary>
        /// New type of "string.Substring" method and used to prevent exception
        /// when "length" value is longer then remain part of text length.
        /// e.g.: value = "something", startIndex = 3 and length = 8
        /// In this case, if standat string.Substring method is used, an exception will be occure.
        /// But, if this method is used, "ething" will be returned.
        /// </summary>
        /// <param name="pValue"></param>
        /// <param name="pStartIndex"></param>
        /// <param name="pLength"></param>
        /// <returns></returns>
        public static string SubstringExt(this string pValue, int pStartIndex, int pLength)
        {
            if (pValue.Substring(pStartIndex).Length > pLength)
            {
                return pValue.Substring(pStartIndex, pLength);
            }
            else if (pStartIndex == 0)
            {
                return pValue;
            }
            else
            {
                return pValue.Substring(pStartIndex);
            }
        }

        /// <summary>
        /// Used to get last character of any string value
        /// </summary>
        /// <returns></returns>
        public static string LastCharacter(this string pValue)
        {
            pValue = pValue.Substring(pValue.Length - 1, 1);
            return pValue;
        }

        /// <summary>
        /// Uset to convert format of any string value to proper case format. 
        /// e.g.: before: "some string VAlue" ; after: "Some String Value"
        /// </summary>
        /// <param name="pText"></param>
        /// <returns></returns>
        public static string ProperCase(this string pValue)
        {
            string txt = pValue.ToLower().Trim().Replace("  ", " ");
            return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(txt);
        }

        /// <summary>
        /// Used to invert any text value by character.
        /// e.g.: "my string".InvertString(' ') = "gnirts ym"
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string InvertString(this string pValue)
        {
            if (pValue == null) return null;
            StringBuilder sb = new StringBuilder();

            if (pValue.Length > 0)
            {
                for (int i = pValue.Length - 1; i >= 0; i--)
                {
                    sb.Append(pValue.Substring(i, 1));
                }
                return sb.ToString();
            }
            else
                return pValue;
        }

        /// <summary>
        /// Used to invert any text value by word.
        /// e.g.: "my string".InvertString(' ') = "string my"
        /// </summary>
        /// <param name="pString"></param>
        /// <param name="pDelimiter"></param>
        /// <returns></returns>
        public static string InvertString(this string pValue, char pDelimiter)
        {
            if (pValue == null) return null;
            string[] parca = pValue.Split(pDelimiter);
            StringBuilder sb = new StringBuilder();

            if (parca.Length > 0)
            {
                for (int i = parca.Length - 1; i >= 0; i--)
                {
                    sb.Append(pDelimiter + parca[i]);
                }
                return sb.Remove(0, 1).ToString();
            }
            else
                return pValue;
        }

        /// <summary>
        /// Used to split any text value by given delimeter character and return rightmost part
        /// </summary>
        /// <param name="pValue"></param>
        /// <param name="pDelimeter"></param>
        /// <returns></returns>
        public static string RSplit(this string pValue, char pDelimeter)
        {
            string[] parca = pValue.Split(pDelimeter);
            return parca[parca.Length - 1].ToString();
        }
        public static string RSplit(this string pValue, string pDelimeter, StringSplitOptions pSplitOption)
        {
            string[] delimeter = { pDelimeter };
            string[] parca = pValue.Split(delimeter, pSplitOption);
            return parca[parca.Length - 1].ToString();
        }
        /// <summary>
        /// Used to split any text value by given delimeter character and return leftmost part
        /// </summary>
        /// <param name="pValue"></param>
        /// <param name="pDelimeter"></param>
        /// <returns></returns>
        public static string LSplit(this string pValue, char pDelimeter)
        {
            return pValue.Split(pDelimeter).GetValue(0).ToString();
        }
        public static string LSplit(this string pValue, string pDelimeter, StringSplitOptions pSplitOption)
        {
            string[] delimeter = { pDelimeter };
            return pValue.Split(delimeter, pSplitOption).GetValue(0).ToString();
        }

        private static string NumberIsVeryBig = "Verilen sayı çok büyük !";
        private static string MoneyUnit = "Lira";
        private static string MoneySubUnit = "Kuruş";
        public static string SayiyiLiraKurusOlarakVer(this string pValue)
        {
            if (pValue.Length == 0) return string.Empty;

            string sonuc = string.Empty;
            string sayi = pValue.ToString();
            string[] parca = sayi.Split(',');
            string lira = parca[0];
            if (lira.Length > 16) throw new ApplicationException(NumberIsVeryBig);
            if (!lira.IsInteger()) return string.Empty;
            sonuc = string.Format("{0}{1}", SayiyiYaziyaCevir(Convert.ToInt64(lira)), MoneyUnit);
            string kurus = string.Empty;
            if (parca.Length > 1)
            {
                kurus = parca[1];
                if (kurus.Length > 16) throw new ApplicationException(NumberIsVeryBig);
                if (!kurus.IsInteger()) return string.Empty;
                sonuc = sonuc + SayiyiYaziyaCevir(Convert.ToInt64(kurus)) + "Kuruş";
            }
            return sonuc;
        }
        public static string SayiyiYaziyaCevir(this long pValue)
        {
            if (pValue.ToString().Length == 0) return string.Empty;
            if (!pValue.IsInteger()) return string.Empty;

            string[] b = new string[10];
            string[] y = new string[10];
            string[] m = new string[5];
            string[] v = new string[16];
            string[] c = new string[4];

            b[0] = "";
            b[1] = "Bir";
            b[2] = "İki";
            b[3] = "Üç";
            b[4] = "Dört";
            b[5] = "Beş";
            b[6] = "Altı";
            b[7] = "Yedi";
            b[8] = "Sekiz";
            b[9] = "Dokuz";

            y[0] = "";
            y[1] = "On";
            y[2] = "Yirmi";
            y[3] = "Otuz";
            y[4] = "Kırk";
            y[5] = "Elli";
            y[6] = "Altmış";
            y[7] = "Yetmiş";
            y[8] = "Seksen";
            y[9] = "Doksan";

            m[0] = "Trilyon";
            m[1] = "Milyar";
            m[2] = "Milyon";
            m[3] = "Bin";
            m[4] = "";

            string sayi = pValue.ToString();
            if (sayi.Length > 16) throw new ApplicationException(NumberIsVeryBig);
            bool negatif = false;
            if (sayi.Substring(0, 1) == "-") negatif = true;
            if (negatif) sayi = sayi.Substring(1);
            sayi = sayi.PadLeft(16, '0');

            for (int i = 1; i < 16; i++)
            {
                v[i] = sayi.Substring(i, 1);
            }

            string s = "";
            string e = "";

            for (int i = 0; i < 5; i++)
            {
                c[1] = v[(i * 3) + 1];
                c[2] = v[(i * 3) + 2];
                c[3] = v[(i * 3) + 3];

                if (c[1] == "0") e = "";
                else if (c[1] == "1") e = "Yüz";
                else e = b[Convert.ToInt32(c[1])] + "Yüz";

                e = e + y[Convert.ToInt32(c[2])] + b[Convert.ToInt32(c[3])];

                if (!String.IsNullOrEmpty(e)) e = e + m[i];
                if (i == 3 && (e == "BirBin")) e = "Bin";
                s = s + e;
            }

            if (String.IsNullOrEmpty(s)) s = "Sıfır";
            if (negatif) s = "Eksi" + s;
            return s;
        }

        public static string RemoveHtmlCharacters(this string pValue)
        {
            return Regex.Replace(pValue, @"<[^>]*>", string.Empty).Replace("&nbsp;", "").Replace("&quot;", ((char)34).ToString());
        }

        public static string RemoveNonNumericCharacters(this string pValue)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < pValue.Length; i++)
                if (Char.IsNumber(pValue[i]))
                    sb.Append(pValue[i]);
            return sb.ToString();
        }

        public static string RemoveNonAlphabeticCharacters(this string pValue)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < pValue.Length; i++)
                if (Char.IsLetter(pValue[i]))
                    sb.Append(pValue[i]);
            return sb.ToString();
        }

        public static string RemoveTurkishCharacters(this string pValue)
        {
            return pValue.ToLower()
                    .Replace("ü", "u").Replace("ç", "c").Replace("ş", "s")
                    .Replace("ğ", "g").Replace("ı", "i").Replace("ö", "o")
                    .Replace("Ü", "U").Replace("Ç", "C").Replace("Ş", "S")
                    .Replace("Ğ", "G").Replace("İ", "I").Replace("Ö", "O");
        }

        /// <summary>
        /// Used to encode Turkish characters for replacement
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string EncodeTurkishCharacters(this string pValue)
        {
            return pValue.Replace("ç", "trchrc")
                    .Replace("Ç", "trchrC")
                    .Replace("ğ", "trchrg")
                    .Replace("Ğ", "trchrG")
                    .Replace("ı", "trchri")
                    .Replace("İ", "trchrI")
                    .Replace("ö", "trchro")
                    .Replace("Ö", "trchrO")
                    .Replace("ü", "trchru")
                    .Replace("Ü", "trchrU")
                    .Replace("ş", "trchrs")
                    .Replace("Ş", "trchrS");
        }

        /// <summary>
        /// Used to decode Turkish characters for replacement
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string DecodeTurkishCharacters(this string pValue)
        {
            return pValue.Replace("trchrc", "ç")
            .Replace("trchrC", "Ç")
            .Replace("trchrg", "ğ")
            .Replace("trchrG", "Ğ")
            .Replace("trchri", "ı")
            .Replace("trchrI", "İ")
            .Replace("trchro", "ö")
            .Replace("trchrO", "Ö")
            .Replace("trchru", "ü")
            .Replace("trchrU", "Ü")
            .Replace("trchrs", "ş")
            .Replace("trchrS", "Ş");
        }

        public static string FixTurkishCharactersForFckEditor(this string pValue)
        {
            return pValue.Replace("&ccedil;", "ç").Replace("&Ccedil;", "Ç").Replace("&ouml;", "ö").Replace("&Ouml;", "Ö").Replace("&uuml;", "ü").Replace("&Uuml;", "Ü");
        }

        /// <summary>
        /// Used to format numbers with comma (,) or point (.) depend on regional settings.
        /// e.g.: 1515786 --> 1.515.786
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string FormatNumber(this long pValue)
        {
            if (pValue > 0)
                return string.Format("{0:0,0}", pValue);
            else
                return pValue.ToString();
        }

        /// <summary>
        /// Used to convert html codes to special characters. This method prepared for Turkish characters.
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string HtmlChrCodeCorrection(this string pValue)
        {
            return pValue.Replace("&#220;", "Ü").Replace("&#252;", "ü").Replace("&#214;", "Ö").Replace("&#246;", "ö").Replace("&#231;", "ç").Replace("&#199;", "Ç").Replace("&nbsp;", " ");
        }

        /// <summary>
        /// Used to remove characters which can be used for injection 
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string RemoveInjectionCharacters(this string pValue)
        {
            return pValue.Replace("<", "&lt;")
            .Replace(">", "&gt;")
            .Replace(" script ", " &#115;cript ")
            .Replace(" SCRIPT ", " &#083;CRIPT ")
            .Replace(" Script ", " &#083;cript ")
            .Replace(" object ", " &#111;bject ")
            .Replace(" OBJECT ", " &#079;BJECT ")
            .Replace(" Object ", " &#079;bject ")
            .Replace(" applet ", " &#097;pplet ")
            .Replace(" APPLET ", " &#065;PPLET ")
            .Replace(" Applet ", " &#065;pplet ")
            .Replace(" embed ", " &#101;mbed ")
            .Replace(" EMBED ", " &#069;MBED ")
            .Replace(" Embed ", " &#069;mbed ")
            .Replace(" event ", " &#101;vent ")
            .Replace(" EVENT ", " &#069;VENT ")
            .Replace(" Event ", " &#069;vent ")
            .Replace(" document ", " &#100;ocument ")
            .Replace(" DOCUMENT ", " &#068;OCUMENT ")
            .Replace(" Document ", " &#068;ocument ")
            .Replace(" cookie ", " &#099;ookie ")
            .Replace(" COOKIE ", " &#067;OOKIE ")
            .Replace(" Cookie ", " &#067;ookie ")

            .Replace("document.cookie", "&#068;ocument.cookie")
            .Replace("javascript:", "javascript ")
            .Replace("vbscript:", "vbscript ")
            .Replace("'", "&#39;");
        }

        /// <summary>
        /// Used to recover characters which are removed from text due to injection possibility
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string RecoverInjectionCharacters(this string pValue)
        {
            return pValue.Replace("&lt;", "<")
            .Replace("&gt;", ">")
            .Replace(" &#115;cript ", " script ")
            .Replace(" &#083;CRIPT ", " SCRIPT ")
            .Replace(" &#083;cript ", " Script ")
            .Replace(" &#111;bject ", " object ")
            .Replace(" &#079;BJECT ", " OBJECT ")
            .Replace(" &#079;bject ", " Object ")
            .Replace(" &#097;pplet ", " applet ")
            .Replace(" &#065;PPLET ", " APPLET ")
            .Replace(" &#065;pplet ", " Applet ")
            .Replace(" &#101;mbed ", " embed ")
            .Replace(" &#069;MBED ", " EMBED ")
            .Replace(" &#069;mbed ", " Embed ")
            .Replace(" &#101;vent ", " event ")
            .Replace(" &#069;VENT ", " EVENT ")
            .Replace(" &#069;vent ", " Event ")
            .Replace(" &#100;ocument ", " document ")
            .Replace(" &#068;OCUMENT ", " DOCUMENT ")
            .Replace(" &#068;ocument ", " Document ")
            .Replace(" &#099;ookie ", " cookie ")
            .Replace(" &#067;OOKIE ", " COOKIE ")
            .Replace(" &#067;ookie ", " Cookie ")
            .Replace("&#068;ocument.cookie", "document.cookie")
            .Replace("&#39;", "'");
        }

        /// <summary>
        /// Used to combine more then one string values by new html line
        /// </summary>
        /// <param name="pValue"></param>
        /// <returns></returns>
        public static string BuildAsString(this string[] pValue)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string str in pValue)
            {
                sb.Append(str + NewLineHtml);
            }
            return sb.ToString();
        }
        public static string BuildAsString(this List<String> pValue)
        {
            StringBuilder sb = new StringBuilder();
            string[] arr = pValue.ToArray();
            foreach (string str in arr)
            {
                sb.Append(str + NewLineHtml);
            }
            return sb.ToString();
        }

        /// <summary>
        /// Used to some htlm properties (fornt, color etc.) to a string value
        /// </summary>
        /// <param name="pValue"></param>
        /// <param name="pColor"></param>
        /// <returns></returns>
        public static string AddHtmlFontTag(this string pValue, string pColor)
        {
            return AddHtmlFontTag(pValue, pColor, uFontSize.smaller, uFontWeight.bold, uFontStyle.normal, uTextDecoration.none, uTextAlign.left, uFontName.Arial);
        }
        public static string AddHtmlFontTag(this string pValue, string pColor, uFontSize pSize, uFontWeight pFontWeight)
        {
            return AddHtmlFontTag(pValue, pColor, pSize, pFontWeight, uFontStyle.normal, uTextDecoration.none, uTextAlign.left, uFontName.Arial);
        }
        public static string AddHtmlFontTag(this string pValue, string pColor, uFontSize pSize, uFontWeight pFontWeight, uFontStyle pFontStyle
                , uTextDecoration pTextDecoration, uTextAlign pAlign, uFontName pFontName)
        {
            string size = pSize.ToString().Replace("xx", "xx-").Replace("x", "x-");
            string weight = pFontWeight.ToString();
            string fontStyle = pFontStyle.ToString();
            string decoration = pTextDecoration.ToString().Replace('_', '-');
            string align = pAlign.ToString();
            string fontName = pFontName.ToString().Replace("_", "").Replace("Sans Serif", "Sans-Serif");

            string s = @"<font style=
                        'color: {1}; 
                        font-size: {2}; 
                        font-weight: {3}; 
                        font-style: {4}; 
                        text-decoration: {5};
                        text-align:{6};'
                        font-family: {7};
                     >
                        {0}
                    </font>";

            s = string.Format(s, pValue, pColor, size, weight, fontStyle, decoration, align, fontName);
            return pValue;
        }

        /// <summary>
        /// Used for replacing by word. 
        /// e.g.: "someone can say me".Replace("me", "123"); = so123one can say 123
        ///       "someone can say me".ReplaceWholeWord("me", "123"); = someone can say 123
        /// </summary>
        /// <param name="pInput"></param>
        /// <param name="pOldValue"></param>
        /// <param name="pNewValue"></param>
        /// <returns></returns>
        public static string ReplaceWholeWord(this string pInput, string pOldValue, string pNewValue)
        {
            string oldValue = string.Format(@"\b{0}\b", pOldValue);
            if (!Regex.IsMatch(pInput, oldValue))
                oldValue = string.Format(@"{0}\b", pOldValue);

            string s = Regex.Replace(pInput, oldValue, pNewValue);
            return s;
        }

        /// <summary>
        /// Used to check if a word exist in a text
        /// </summary>
        /// <param name="pInput">Text to search in</param>
        /// <param name="pValue">Value to find in text</param>
        /// <returns></returns>
        public static bool IsContains(this string pInput, string pValue)
        {
            string value = string.Format(@"\b{0}\b", pValue);
            if (Regex.IsMatch(pInput, value)) return true;

            value = string.Format(@"{0}\b", pValue);
            return Regex.IsMatch(pInput, value);
        }

        /// <summary>
        /// Used to remove values which given by pValue2 from values which given by pValue1
        /// e.g.: pValue1 = "name sirname place date"
        ///       pValue2 = "place"
        ///       result = "name sirname date"
        /// </summary>
        /// <param name="pValue1"></param>
        /// <param name="pValue2"></param>
        /// <returns></returns>
        public static string Except(this string pValue1, string pValue2)
        {
            return Except(pValue1, pValue2, ',');
        }
        public static string Except(this string pValue1, string pValue2, char pDelimiter)
        {
            string[] s1 = pValue1.Split(pDelimiter);
            string[] s2 = pValue2.Split(pDelimiter);

            string s = string.Empty;

            foreach (string item in s1)
            {
                if (!s2.Contains(item)) s = string.Format("{0}{1}{2}", s, pDelimiter, item);
            }
            if (!String.IsNullOrEmpty(s)) s = s.TrimStart(pDelimiter);
            return s;
        }

        /// <summary>
        /// Used to remove values which given by pValue2 from values which given by pValue1
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pValue1"></param>
        /// <param name="pValue1"></param>
        /// <returns></returns>
        public static List<T> Except<T>(this List<T> pValue1, List<T> pValue2)
        {
            List<T> s = new List<T>();

            foreach (T item in pValue1)
            {
                if (!pValue2.Contains(item)) s.Add(item);
            }
            return s;
        }

        /// <summary>
        /// Used to produce the desired length arbitrary text
        /// </summary>
        /// <param name="pCharacterType"></param>
        /// <param name="pLength"></param>
        /// <returns></returns>
        public static string GenerateRandomString(CharacterTypes pCharacterType, int pLength)
        {
            string pw = string.Empty;
            int length = pLength - 1;

            int rdNumber = 0;
            int minValue = 0;
            int maxValue = 0;

            int dMin = 48;
            int dMax = 57;
            int uLMin = 65;
            int uLMax = 90;
            int lLMin = 97;
            int lLMax = 122;

            Random rnd = new Random();

            do
            {
                switch (pCharacterType)
                {
                    case CharacterTypes.OnlyDigits:
                        minValue = dMin;
                        maxValue = dMax;
                        rdNumber = rnd.Next(minValue, maxValue);
                        break;
                    case CharacterTypes.UpperLetters:
                        minValue = uLMin;
                        maxValue = uLMax;
                        rdNumber = rnd.Next(minValue, maxValue);
                        break;
                    case CharacterTypes.LowerLetters:
                        minValue = lLMin;
                        maxValue = lLMax;
                        rdNumber = rnd.Next(minValue, maxValue);
                        break;
                    case CharacterTypes.UpperLowerLetters:
                        minValue = uLMin;
                        maxValue = lLMax;
                        do
                            rdNumber = rnd.Next(minValue, maxValue);
                        while (!((rdNumber >= uLMin & rdNumber <= uLMax) | (rdNumber >= lLMin & rdNumber <= lLMax)));
                        break;
                    case CharacterTypes.DigitLowerLetters:
                        minValue = dMin;
                        maxValue = lLMax;
                        do
                            rdNumber = rnd.Next(minValue, maxValue);
                        while (!((rdNumber >= dMin & rdNumber <= dMax) | (rdNumber >= lLMin & rdNumber <= lLMax)));
                        break;
                    case CharacterTypes.DigitUpperLetters:
                        minValue = dMin;
                        maxValue = uLMax;
                        do
                            rdNumber = rnd.Next(minValue, maxValue);
                        while (!((rdNumber >= dMin & rdNumber <= dMax) | (rdNumber >= uLMin & rdNumber <= uLMax)));
                        break;
                    case CharacterTypes.DigitUpperLowerLetters:
                        minValue = dMin;
                        maxValue = lLMax;
                        do
                            rdNumber = rnd.Next(minValue, maxValue);
                        while (!((rdNumber >= dMin & rdNumber <= dMax) | (rdNumber >= uLMin & rdNumber <= uLMax) | (rdNumber >= lLMin & rdNumber <= lLMax)));
                        break;
                }

                pw = string.Format("{0}{1}", pw, (char)rdNumber);

            } while (pw.Length <= length);

            return pw;
        }

        /// <summary>
        /// Used to produce the desired length arbitrary Symbol "(,$,=,%,-,!,*,?,+,)"
        /// </summary>
        /// <param name="pLength"></param>
        /// <returns></returns>
        public static string GenerateRandomSymbol(int pLength)
        {
            string pw = string.Empty;
            string symbol = string.Empty;
            int length = pLength - 1;

            do
            {
                string rdnNo = GenerateRandomString(CharacterTypes.OnlyDigits, 1);
                switch (rdnNo)
                {
                    case "0": symbol = "("; break;
                    case "1": symbol = "$"; break;
                    case "2": symbol = "="; break;
                    case "3": symbol = "%"; break;
                    case "4": symbol = "-"; break;
                    case "5": symbol = "!"; break;
                    case "6": symbol = "*"; break;
                    case "7": symbol = "?"; break;
                    case "8": symbol = "+"; break;
                    case "9": symbol = ")"; break;
                    default: symbol = "!"; break;
                }

                pw = string.Format("{0}{1}", pw, symbol);

            } while (pw.Length <= length);

            return pw;
        }
    }
}
